按间隔分组值
group values in intervals
我有一个包含零和一的 pandas 系列:
df1 = pd.Series([ 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0])
df1
Out[3]:
0 0
1 0
2 0
3 0
4 0
5 1
6 1
7 1
8 0
9 0
10 0
我想创建一个数据帧 df2,其中包含具有相同值的间隔的开始和结束,以及关联的值...本例中的 df2 应该是...
df2
Out[5]:
Start End Value
0 0 4 0
1 5 7 1
2 8 10 0
我的尝试是:
from operator import itemgetter
from itertools import groupby
a=[next(group) for key, group in groupby(enumerate(df1), key=itemgetter(1))]
df2 = pd.DataFrame(a,columns=['Start','Value'])
但我不知道如何获得 'End' 索引
您可以使用pd.Series.diff()
方法来识别起始索引:
df2 = pd.DataFrame()
df2['Start'] = df1[df1.diff().fillna(1) != 0].index
然后据此计算结束索引:
df2['End'] = [e - 1 for e in df2['Start'][1:]] + [df1.index.max()]
最后收集关联值:
df2['Value'] = df1[df2['Start']].values
输出
Start End Value
0 0 4 0
1 5 7 1
2 8 10 0
您要查找的是 获取 groupby 中的第一个和最后一个值
import pandas as pd
def first_last(df):
return df.ix[[0,-1]]
df = pd.DataFrame([3]*4+[4]*4+[1]*4+[3]*3,columns=['value'])
print df
df['block'] = (df.value.shift(1) != df.value).astype(int).cumsum()
df = df.reset_index().groupby(['block','value'])['index'].agg(['first', 'last']).reset_index()
del df['block']
print df
您可以使用 shift 和 cumsum 进行分组并找到第一个和最后一个有效索引
df2 = df1.groupby((df1 != df1.shift()).cumsum()).apply(lambda x: np.ravel([x.index[0], x.index[-1], x.unique()]))
df2 = pd.DataFrame(df2.values.tolist()).rename(columns = {0: 'Start', 1: 'End',2:'Value'})
你得到
Start End Value
0 0 4 0
1 5 7 1
2 8 10 0
你可以groupby
by Series
which is create by cumsum
of shifted Series
df1
by shift
.
然后apply
custum function and last reshape by unstack
.
s = df1.ne(df1.shift()).cumsum()
df2 = df1.groupby(s).apply(lambda x: pd.Series([x.index[0], x.index[-1], x.iat[0]],
index=['Start','End','Value']))
.unstack().reset_index(drop=True)
print (df2)
Start End Value
0 0 4 0
1 5 7 1
2 8 10 0
通过 agg
与 first
和 last
聚合的另一种解决方案,但需要更多代码来处理所需输出的输出。
s = df1.ne(df1.shift()).cumsum()
d = {'first':'Start','last':'End'}
df2 = df1.reset_index(name='Value') \
.groupby([s, 'Value'])['index'] \
.agg(['first','last']) \
.reset_index(level=0, drop=True) \
.reset_index() \
.rename(columns=d) \
.reindex_axis(['Start','End','Value'], axis=1)
print (df2)
Start End Value
0 0 4 0
1 5 7 1
2 8 10 0
我有一个包含零和一的 pandas 系列:
df1 = pd.Series([ 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0])
df1
Out[3]:
0 0
1 0
2 0
3 0
4 0
5 1
6 1
7 1
8 0
9 0
10 0
我想创建一个数据帧 df2,其中包含具有相同值的间隔的开始和结束,以及关联的值...本例中的 df2 应该是...
df2
Out[5]:
Start End Value
0 0 4 0
1 5 7 1
2 8 10 0
我的尝试是:
from operator import itemgetter
from itertools import groupby
a=[next(group) for key, group in groupby(enumerate(df1), key=itemgetter(1))]
df2 = pd.DataFrame(a,columns=['Start','Value'])
但我不知道如何获得 'End' 索引
您可以使用pd.Series.diff()
方法来识别起始索引:
df2 = pd.DataFrame()
df2['Start'] = df1[df1.diff().fillna(1) != 0].index
然后据此计算结束索引:
df2['End'] = [e - 1 for e in df2['Start'][1:]] + [df1.index.max()]
最后收集关联值:
df2['Value'] = df1[df2['Start']].values
输出
Start End Value
0 0 4 0
1 5 7 1
2 8 10 0
您要查找的是 获取 groupby 中的第一个和最后一个值
import pandas as pd
def first_last(df):
return df.ix[[0,-1]]
df = pd.DataFrame([3]*4+[4]*4+[1]*4+[3]*3,columns=['value'])
print df
df['block'] = (df.value.shift(1) != df.value).astype(int).cumsum()
df = df.reset_index().groupby(['block','value'])['index'].agg(['first', 'last']).reset_index()
del df['block']
print df
您可以使用 shift 和 cumsum 进行分组并找到第一个和最后一个有效索引
df2 = df1.groupby((df1 != df1.shift()).cumsum()).apply(lambda x: np.ravel([x.index[0], x.index[-1], x.unique()]))
df2 = pd.DataFrame(df2.values.tolist()).rename(columns = {0: 'Start', 1: 'End',2:'Value'})
你得到
Start End Value
0 0 4 0
1 5 7 1
2 8 10 0
你可以groupby
by Series
which is create by cumsum
of shifted Series
df1
by shift
.
然后apply
custum function and last reshape by unstack
.
s = df1.ne(df1.shift()).cumsum()
df2 = df1.groupby(s).apply(lambda x: pd.Series([x.index[0], x.index[-1], x.iat[0]],
index=['Start','End','Value']))
.unstack().reset_index(drop=True)
print (df2)
Start End Value
0 0 4 0
1 5 7 1
2 8 10 0
通过 agg
与 first
和 last
聚合的另一种解决方案,但需要更多代码来处理所需输出的输出。
s = df1.ne(df1.shift()).cumsum()
d = {'first':'Start','last':'End'}
df2 = df1.reset_index(name='Value') \
.groupby([s, 'Value'])['index'] \
.agg(['first','last']) \
.reset_index(level=0, drop=True) \
.reset_index() \
.rename(columns=d) \
.reindex_axis(['Start','End','Value'], axis=1)
print (df2)
Start End Value
0 0 4 0
1 5 7 1
2 8 10 0